package ue.client.networking;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class Cryptography {
	
	public static Random random = new Random();
	
	//Diffie-Hellman
	public static BigInteger generateDHPublicP(int bitLength, int certainty) {
		return new BigInteger(bitLength, certainty, random);
	}
	
	public static BigInteger generateDHPublicG(BigInteger p) {
		return new BigInteger(p.bitLength(), random).mod(p);
	}
	
	public static BigInteger generateDHPrivateNumber(BigInteger p) {
		return new BigInteger(p.bitLength(), random).mod(p);
	}
	
	public static BigInteger calculateDHTransferNumber(BigInteger a, BigInteger p, BigInteger g) {
		return g.modPow(a, p);
	}
	
	public static BigInteger calculateDHKey(BigInteger b, BigInteger a, BigInteger p) {
		return b.modPow(a, p);
	}
	
	//AES
	public static SecretKeySpec generateAESKey(BigInteger key) {
		return new SecretKeySpec(Arrays.copyOf(key.toByteArray(), 16), "AES");
	}
	
	public static byte[] encodeAES(SecretKeySpec key, byte[] bytes) {
		Cipher cipher = null;
		
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		
		try {
			cipher.init(Cipher.ENCRYPT_MODE, key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		
		try {
			return cipher.doFinal(bytes);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public static byte[] decodeAES(SecretKeySpec key, byte[] bytes) {
		Cipher cipher = null;
		
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		
		try {
			cipher.init(Cipher.DECRYPT_MODE, key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		
		try {
			return cipher.doFinal(bytes);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	//Prime Generation
	public static int generatePrime(int max) {
		for(int i = max; i > 2; i--) {
			if(isPrime(i))
				return i;
		}
		return 0;
	}
	
	public static int generateRandomPrime(int max) {
		int n = 0;
		
		do {
			n = random.nextInt(max);
		} while(!isPrime(n));
		
		return n;
	}
	
	public static boolean isPrime(int n) {
		for(int i = 3; i < n; i += 2) {
			if(n % i == 0) {
				return false;
			}
		}
		return true;
	}
	
	public static String bytesToHex(byte[] hashValue) {
	    Formatter form = new Formatter();
	    for (int i = 0; i < hashValue.length; i++)
	    	form.format("%02x", hashValue[i]);
	    String out = form.toString();
	    form.close();
	    
	    return out;
	}
}
